
Namespace convertor
    Public Module convertor

        Private Delegate Sub tobytesWriter(Of t)(ByVal ptr As Object, ByVal start As Int32, ByVal value As t)

        Private Function tobytesImpl(Of t)(ByVal i As t, ByRef b As bytes, _
                                           ByRef writer As tobytesWriter(Of t)) As Boolean
            If b Is Nothing Then
                b = New bytes()
            End If
            If b.size() <> sizeof(i) Then
                b.size = sizeof(i)
            End If
            writer(+b, 0, i)
            Return True
        End Function

        Public Function tobytes(ByVal i As Byte, ByRef b As bytes) As Boolean
            Return tobytesImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteByte)
        End Function

        Public Function tobytes(ByVal i As Int16, ByRef b As bytes) As Boolean
            Return tobytesImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt16)
        End Function

        Public Function tobytes(ByVal i As Int32, ByRef b As bytes) As Boolean
            Return tobytesImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt32)
        End Function

        Public Function tobytes(ByVal i As Int64, ByRef b As bytes) As Boolean
            Return tobytesImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt64)
        End Function

        Public Function toutf8bytes(ByVal i As String, ByRef b As bytes) As Boolean
            b = encoding.utf8.GetBytes(i)
            Return True
        End Function

        Public Function tobytes(ByVal i As Int32) As bytes
            Dim o As bytes = Nothing
            If tobytes(i, o) Then
                Return o
            Else
                'this call should not fail, so debugassert here
                debugassert(False, "cannot convert int32 " + Convert.ToString(i) + " to bytes.")
                Return Nothing
            End If
        End Function

        Public Function tobytes(ByVal i As Int64) As bytes
            Dim o As bytes = Nothing
            If tobytes(i, o) Then
                Return o
            Else
                'this call should not fail, so debugassert here
                debugassert(False, "cannot convert int64 " + Convert.ToString(i) + " to bytes.")
                Return Nothing
            End If
        End Function

#If RETIRED Then
        Private Function tobyteArrayImpl(Of t)(ByVal i As t, ByRef b() As Byte _
                                            , ByRef writer As tobytesWriter(Of t)) As Boolean
            If b Is Nothing OrElse b.Length() <> sizeof(i) Then
                ReDim b(sizeof(i) - 1)
            End If
            writer(b, 0, i)
            Return True
        End Function

        Public Function tobyteArray(ByVal i As Byte, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteByte)
        End Function

        Public Function tobyteArray(ByVal i As Int16, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt16)
        End Function

        Public Function tobyteArray(ByVal i As Int32, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt32)
        End Function

        Public Function tobyteArray(ByVal i As Int64, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt64)
        End Function
#End If

        Private Delegate Function frombyteReader(Of t)(ByVal ptr As Object, ByVal offset As Int32) As t

        Private Function frombytesImpl(Of t)(ByVal b As bytes, ByRef o As t _
                                            , ByRef reader As frombyteReader(Of t)) As Boolean
            If b Is Nothing OrElse b.size < sizeof(o) Then
                Return False
            Else
                o = reader(+b, 0)
                Return True
            End If
        End Function

        Public Function toint8(ByVal b As bytes, ByRef o As Byte) As Boolean
            Return tobyte(b, o)
        End Function

        Public Function tobyte(ByVal b As bytes, ByRef o As Byte) As Boolean
            Return frombytesImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadByte)
        End Function

        Public Function toint16(ByVal b As bytes, ByRef o As Int16) As Boolean
            Return frombytesImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadInt16)
        End Function

        Public Function toint32(ByVal b As bytes, ByRef o As Int32) As Boolean
            Return frombytesImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadInt32)
        End Function

        Public Function toint64(ByVal b As bytes, ByRef o As Int64) As Boolean
            Return frombytesImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadInt64)
        End Function

        Public Function toutf8string(ByVal bs() As Byte, ByVal start As Int64, ByVal len As Int64, _
                                     ByRef o As String) As Boolean
            Try
                o = encoding.utf8().GetString(bs, start, len)
                Return True
            Catch
                Return False
            End Try
        End Function

        Public Function toutf8string(ByVal bs() As Byte, ByVal start As Int64, ByVal len As Int64) As String
            Dim s As String = Nothing
            If toutf8string(bs, start, len, s) Then
                Return s
            Else
                Return Nothing
            End If
        End Function

        Public Function toutf8string(ByVal bs() As Byte, ByRef o As String) As Boolean
            Return Not bs Is Nothing AndAlso toutf8string(bs, 0, bs.Length(), o)
        End Function

        Public Function toutf8string(ByVal bs() As Byte) As String
            Dim s As String = Nothing
            Return ifoper(toutf8string(bs, s), s, Nothing)
        End Function

        Public Function toutf8string(ByVal b As bytes, ByRef o As String) As Boolean
            Return Not b Is Nothing AndAlso toutf8string(+b, 0, b.size(), o)
        End Function

        Public Function toutf8string(ByVal b As bytes) As String
            Dim s As String = Nothing
            Return ifoper(toutf8string(b, s), s, Nothing)
        End Function

        Public Function tohexchar(ByVal b As Byte, ByRef c As Char) As Boolean
            If b < 10 Then
                c = Convert.ToChar(b + Convert.ToInt32(character._0))
                Return True
            ElseIf b < 16 Then
                c = Convert.ToChar(b + Convert.ToInt32(character.a) - 10)
                Return True
            Else
                Return False
            End If
        End Function

        Public Function tohexchar(ByVal b As Byte) As Char
            Dim c As Char = Nothing
            Return ifoper(tohexchar(b, c), c, character.null)
        End Function

        Public Function tohexstring(ByVal b As Byte, ByRef o As String) As Boolean
            Dim c1 As Char = Nothing
            Dim c2 As Char = Nothing
            If debugassert(tohexchar(b >> 4, c1) AndAlso tohexchar(b And ((1 << 4) - 1), c2), _
                           "a byte should always be able to convert to two hex charactors, b = " + _
                           Convert.ToString(b)) Then
                o = c1 + c2
                Return True
            Else
                Return False
            End If
        End Function

        Public Function tohexstring(ByVal b As Byte) As String
            Dim s As String = Nothing
            Return ifoper(tohexstring(b, s), s, Nothing)
        End Function

        Public Function tohexstring(ByVal bs() As Byte, ByVal start As Int64, ByVal len As Int64, _
                                    ByRef o As String) As Boolean
            If bs Is Nothing OrElse start < 0 OrElse len < 0 OrElse len > maxInt32 OrElse bs.Length() < start + len Then
                Return False
            Else
                Dim sb As Text.StringBuilder = Nothing
                sb = New Text.StringBuilder(Convert.ToInt32(len))
                Dim i As Int64
                For i = start To start + len - 1
                    sb.Append(tohexstring(bs(i)))
                Next

                o = Convert.ToString(sb)
                Return True
            End If
        End Function

        Public Function tohexstring(ByVal bs() As Byte, ByVal start As Int64, ByVal len As Int64) As String
            Dim s As String = Nothing
            Return ifoper(tohexstring(bs, start, len, s), s, Nothing)
        End Function

        Public Function tohexstring(ByVal bs() As Byte, ByRef o As String) As Boolean
            Return Not bs Is Nothing AndAlso tohexstring(bs, 0, bs.Length(), o)
        End Function

        Public Function tohexstring(ByVal bs() As Byte) As String
            Dim s As String = Nothing
            Return ifoper(tohexstring(bs, s), s, Nothing)
        End Function

        Public Function tohexstring(ByVal b As bytes, ByRef o As String) As Boolean
            Return Not b Is Nothing AndAlso tohexstring(+b, 0, b.size(), o)
        End Function

        Public Function tohexstring(ByVal b As bytes) As String
            Dim s As String = Nothing
            Return ifoper(tohexstring(b, s), s, Nothing)
        End Function

#If RETIRED Then
        Private Function frombyteArrayImpl(Of t)(ByVal b() As Byte, ByRef o As t _
                                                , ByRef reader As frombyteReader(Of t)) As Boolean
            If b Is Nothing OrElse b.Length < sizeof(o) Then
                Return False
            Else
                o = reader(b, 0)
                Return True
            End If
        End Function

        Public Function toint8(ByVal b() As Byte, ByRef o As Byte) As Boolean
            Return tobyte(b, o)
        End Function

        Public Function tobyte(ByVal b() As Byte, ByRef o As Byte) As Boolean
            Return frombyteArrayImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadByte)
        End Function

        Public Function toint16(ByVal b() As Byte, ByRef o As Int16) As Boolean
            Return frombyteArrayImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadInt16)
        End Function

        Public Function toint32(ByVal b() As Byte, ByRef o As Int32) As Boolean
            Return frombyteArrayImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadInt32)
        End Function

        Public Function toint64(ByVal b() As Byte, ByRef o As Int64) As Boolean
            Return frombyteArrayImpl(b, o, AddressOf System.Runtime.InteropServices.Marshal.ReadInt64)
        End Function
#End If

        Public Function tobyte(ByVal s As String, ByRef i As Byte, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToByte(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function tobyte(ByVal i As UInt32, ByRef o As Byte) As Boolean
            Try
                o = Convert.ToByte(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function tosbyte(ByVal s As String, ByRef i As SByte, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToSByte(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint8(ByVal s As String, ByRef i As SByte, Optional ByVal frombase As Int32 = 10) As Boolean
            Return tosbyte(s, i, frombase)
        End Function

        Public Function toint16(ByVal s As String, ByRef i As Int16, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToInt16(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint32(ByVal s As String, ByRef i As Int32, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToInt32(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint32(ByVal obj As Object, ByRef i As Int32) As Boolean
            Try
                i = Convert.ToInt32(obj)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function touint32(ByVal s As String, ByRef i As UInt32, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToUInt32(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function touint64(ByVal s As String, ByRef i As UInt64, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToUInt64(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint64(ByVal s As String, ByRef i As Int64, Optional ByVal frombase As Int32 = 10) As Boolean
            Try
                i = Convert.ToInt64(s, frombase)
            Catch
                Return False
            End Try

            Return True
        End Function

        'let me make it be the safe converting
        Public Function toint64(ByVal d As Double, ByRef i As Int64) As Boolean
            Try
                i = Convert.ToInt64(d)
            Catch
                Return False
            End Try

            Return d = i
        End Function

        Public Function todouble(ByVal obj As Object, ByRef i As Double) As Boolean
            Try
                i = Convert.ToDouble(obj)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toboolean(ByVal i As Int32, ByRef o As Boolean) As Boolean
            Try
                o = Convert.ToBoolean(i)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toboolean(ByVal i As UInt32, ByRef o As Boolean) As Boolean
            Try
                o = Convert.ToBoolean(i)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toboolean(ByVal i As Int64, ByRef o As Boolean) As Boolean
            Try
                o = Convert.ToBoolean(i)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toboolean(ByVal i As UInt64, ByRef o As Boolean) As Boolean
            Try
                o = Convert.ToBoolean(i)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toboolean(ByVal s As String, ByRef i As Boolean) As Boolean
            Try
                i = Convert.ToBoolean(s)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function trans(Of t, it)(ByVal i As it, Optional ByVal requireAssert As Boolean = True) As t
            Return cast(Of t, it)(i, requireAssert)
        End Function

        Public Function trans(Of t)(ByVal i As Object, Optional ByVal requireAssert As Boolean = True) As t
            Return cast(Of t)(i, requireAssert)
        End Function

        Private Sub cast_assert(Of T)(ByVal i As Object, ByVal rst As Boolean, ByVal requireAssert As Boolean)
            If Not rst AndAlso requireAssert Then
                'may not be able to get type from i, if i is nothing
                On Error Resume Next
                'the call GetType() and GetType(t) uses lots of time, so in this way
                assert(False, "cannot convert from " + i.GetType().FullName + " to " + GetType(T).FullName)
            End If
        End Sub

        Public Function cast(Of t)(ByVal i As Object, Optional ByVal requireAssert As Boolean = True) As t
            Dim o As t = Nothing
            cast_assert(Of t)(i, cast(Of t)(i, o), requireAssert)
            Return o
        End Function

        'use in this way
        'dim i as thisClass = new thisClass()
        'cast(of otherClass, otherClass)(i)
        'so if there is a ctype from thisClass to otherClass, it will be OK to translate
        'use directly ctype may fail
        'use cast(of object)(i, requireAssert) can make it safer? cannot sure about it.
        Public Function cast(Of t, it)(ByVal i As it, Optional ByVal requireAssert As Boolean = True) As t
            'Return cast(Of t)(cast(Of Object)(i, requireAssert), requireAssert)
            Dim o As t = Nothing
            cast_assert(Of t)(i, cast(Of t, it)(i, o), requireAssert)
            Return o
        End Function

        Public Function cast(Of t)(ByVal i As Object, ByRef o As t) As Boolean
            If i Is Nothing Then
                o = Nothing
                Return True
            ElseIf istype(Of t)(i) Then
                o = i
                Return True
            End If
            Try
                o = DirectCast(i, t)
                Return True
            Catch
                Try
                    o = CType(i, t)
                    Return True
                Catch
                    o = Nothing
                    Return False
                End Try
            End Try
            '1. may not be able to CType(i, t)
            '2. may not be able to GetType(t).IsValueType?
            'On Error Resume Next
            'o = CType(i, t)
            'Return Not o Is Nothing OrElse GetType(t).IsValueType
        End Function

        Public Function cast(Of t, it)(ByVal i As it, ByRef o As t) As Boolean
            Return cast(Of t)(i, o)
        End Function

        Public Function todouble(ByVal s As String, ByRef o As Double) As Boolean
            Try
                o = Convert.ToDouble(s)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint64(ByVal obj As Object, ByRef i As Int64) As Boolean
            Try
                i = Convert.ToInt64(obj)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint32(ByVal i As Int64, ByRef o As Int32) As Boolean
            Try
                o = Convert.ToInt32(i)
            Catch
                Return False
            End Try

            Return True
        End Function

        Public Function toint32(ByVal i As Int64) As Int32
            Dim rtn As Int32
            If toint32(i, rtn) Then
                Return rtn
            Else
                Return npos
            End If
        End Function

        Public Function toint32(ByVal i As UInt32, ByRef o As Int32) As Boolean
            If i > maxInt32 Then
                o = Convert.ToInt64(i) - maxUInt32 - 1
            Else
                o = i
            End If
            Return True
        End Function

        Public Function toint32(ByVal i As UInt32) As Int32
            Dim rtn As Int32
            If toint32(i, rtn) Then
                Return rtn
            Else
                Return npos
            End If
        End Function

        Public Function toint32(ByVal s As String) As Int32
            Dim rtn As Int32
            If toint32(s, rtn) Then
                Return rtn
            Else
                Return npos
            End If
        End Function

        Public Function tochar(ByVal i As Int64, ByRef c As Char) As Boolean
            Try
                c = Convert.ToChar(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function tochar(ByVal i As Int64) As Char
            Dim c As Char
            If tochar(i, c) Then
                Return c
            Else
                Return character.null
            End If
        End Function

        Public Function tochar(ByVal i As UInt32, ByRef c As Char) As Boolean
            Try
                c = Convert.ToChar(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function tochar(ByVal i As UInt32) As Char
            Dim c As Char
            If tochar(i, c) Then
                Return c
            Else
                Return character.null
            End If
        End Function

        Public Function tochar(ByVal i As Int32, ByRef c As Char) As Boolean
            Try
                c = Convert.ToChar(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function tochar(ByVal i As Int32) As Char
            Dim c As Char
            If tochar(i, c) Then
                Return c
            Else
                Return character.null
            End If
        End Function

        Public Function toint32(ByVal i As Char, ByRef o As Int32) As Boolean
            Try
                o = Convert.ToInt32(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function toint32(ByVal i As Char) As Int32
            Dim o As Int32
            If toint32(i, o) Then
                Return o
            Else
                Return npos
            End If
        End Function

        Public Function touint16(ByVal i As Int32, ByRef o As UInt16) As Boolean
            Try
                o = Convert.ToUInt16(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function touint16(ByVal i As Int32) As UInt16
            Dim o As UInt16
            If touint16(i, o) Then
                Return o
            Else
                Return 0
            End If
        End Function

        Public Function touint16(ByVal i As UInt32, ByRef o As UInt16) As Boolean
            Try
                o = Convert.ToUInt16(i)
            Catch
                Return False
            End Try
            Return True
        End Function

        Public Function touint16(ByVal i As UInt32) As UInt16
            Dim o As UInt16
            If touint16(i, o) Then
                Return o
            Else
                Return 0
            End If
        End Function

        Public Function toint8(ByVal c As Char, ByRef o As Byte) As Boolean
            If isDBCDigit(c) Then
                o = Asc(c) - Asc(character._0)
                Return True
            ElseIf isSBCDigit(c) Then
                o = Asc(c) - Asc(character.sbc0)
                Return True
            Else
                Return False
            End If
        End Function

        Public Function toint8(ByVal c As Char) As Byte
            Dim o As Byte
            If toint8(c, o) Then
                Return o
            Else
                Return 0
            End If
        End Function

        Public Sub castUnittest()
            Console.WriteLine(convertor.cast(Of Int32)("0"))
            Console.WriteLine(convertor.cast(Of Int64)(0))
            Console.WriteLine(convertor.cast(Of Int64)("abc"))
        End Sub

    End Module
End Namespace
